﻿namespace VoiceDominion
{
    using System;
    using System.Collections.Generic;
    using System.Configuration;
    using System.Globalization;
    using System.ServiceModel.Channels;

    public class ISYHomeAutomation : IModule, IDisposable
    {
        private ISY.UDIServices_PortTypeClient client;
        private bool disposed = false; 

        public ISYHomeAutomation()
        {
            //// ISY Config
            var binding = new CustomBinding();
            binding.Namespace = "xmlns:s=\"http://www.w3.org/2003/05/soap-envelope\"";

            binding.Elements.Add(new TextMessageEncodingBindingElement());

            HttpTransportBindingElement httpBinding = new HttpTransportBindingElement();
            httpBinding.AuthenticationScheme = System.Net.AuthenticationSchemes.Basic;
            httpBinding.Realm = "/";
            binding.Elements.Add(httpBinding);

            System.ServiceModel.EndpointAddress endpoint = new System.ServiceModel.EndpointAddress(ConfigurationManager.AppSettings["ISYAPIEndpoint"]);

            this.client = new ISY.UDIServices_PortTypeClient(binding, endpoint);
            this.client.ClientCredentials.UserName.UserName = ConfigurationManager.AppSettings["ISYUsername"];
            this.client.ClientCredentials.UserName.Password = ConfigurationManager.AppSettings["ISYPassword"];
        }

        public void ProcessCommand(Dictionary<string, string> parameters)
        {
            if (parameters.ContainsKey("device") && parameters.ContainsKey("command"))
            {
                System.Threading.ThreadPool.QueueUserWorkItem(
                delegate
                {
                    Console.WriteLine("Sending command to ISY...");
                    this.SendCommandToISY(parameters["device"], parameters["command"]);
                    Console.WriteLine("Done sending command to ISY...");
                }, 
                null);

                Speech.Instance.AudioPlayer.PlaySync();
                ////tts.SpeakAsync(e.Result.Text);
            }
            else if (parameters.ContainsKey("command"))
            {
                switch (parameters["command"])
                {
                    case "ListNodes":
                        Speech.Instance.TextToSpeech.SpeakAsync("Listing nodes");
                        this.ListNodes();
                        break;
                    default:
                        ////TODO: log
                        Console.WriteLine(string.Format(CultureInfo.InvariantCulture, "Unrecognized command: {0}", parameters["command"]));
                        break;
                }
            }
        }

        public void SendCommandToISY(string device, string command)
        {
            ISY.UDIServiceParam svc = new ISY.UDIServiceParam();
            svc.control = command;
            svc.node = device;
            ////svc.action = "50";
            ////svc.flag = ISYTest.ISYTestForm.NODE_IS_DEVICE;
            try
            {
                this.client.UDIService(svc);
            }
            catch (Exception ex)
            {
                Speech.Instance.TextToSpeech.SpeakAsync(string.Format(CultureInfo.InvariantCulture, "I have encountered an error sending the command to the server. The error was {0}", ex.Message));
                Console.WriteLine(ex.ToString());
            }
        }

        public void Dispose()
        {
            this.Dispose(true);

            // Call SupressFinalize in case a subclass implements a finalizer.
            GC.SuppressFinalize(this);
        }

        // http://msdn.microsoft.com/en-us/library/fs2xkftw(v=vs.110).aspx
        public void Dispose(bool disposing)
        {
            // If you need thread safety, use a lock around these  
            // operations, as well as in your methods that use the resource. 
            if (!this.disposed)
            {
                if (disposing)
                {
                    if (this.client != null)
                    {
                        this.client.Close();
                    }
                }

                this.client = null;

                this.disposed = true;
            }
        }

        private void ListNodes()
        {
            var nodes = this.client.GetNodesConfig(new ISY.Empty());
            this.DisplayNodeInfo(nodes);
        }

        private void DisplayNodeInfo(ISY.nodes nodeList)
        {
            string line;

            Console.Write("ISY Devices and Scenes" + Environment.NewLine);
            Console.Write("----------------------" + Environment.NewLine);

            foreach (ISY.node node in nodeList.node)
            {
                line = node.name + " [" + node.address + "]" + Environment.NewLine;
                Console.Write(line);
            }

            Console.Write(Environment.NewLine);

            foreach (ISY.group group in nodeList.group)
            {
                line = group.name + " [" + group.address + "]" + Environment.NewLine;
                Console.Write(line);
            }

            Console.Write(Environment.NewLine);
        }
    }
}
